﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Web;
using System.Web.Caching;
using System.Threading;
using System.Globalization;

namespace NLBS
{
    /// <summary>
    /// This is a replacement for the <see cref="Cache"/> object. 
    /// Use this when caching content.  This ensures content is 
    /// cached according to key and Locale.
    /// </summary>
    public class ContentCache : IEnumerable
    {
        System.Web.Caching.Cache cache;
       
        /// <summary>
        /// Instantiates the specified content cache from the specific <see cref="HttpContext"/>. 
        /// At some point, we might consider replacing HttpContext with a type we can extend.
        /// </summary>
        /// <returns></returns>
        public static ContentCache Instantiate()
        {
            //Check per-request cache.
            
            ContentCache cache = HttpContext.Current.Items["ContentCache"] as ContentCache;
            if (cache != null)
                return cache;

            cache = new ContentCache(HttpContext.Current.Cache);
            //Per-Request Cache.
            HttpContext.Current.Items["ContentCache"] = cache;
            return cache;
        }

        private ContentCache() { }

        /// <summary>
        /// Initializes a new instance of the <see cref="ContentCache"/> class. 
        /// The specified <see cref="Cache"/> instance is wrapped by this instance.
        /// </summary>
        /// <param name="cache">The cache.</param>
        private ContentCache(System.Web.Caching.Cache cache)
        {
            this.cache = cache;
        }

        //Returns a language aware cache key.
        private string GetCacheKey(string key)
        {
            return key + ":" + Thread.CurrentThread.CurrentCulture.LCID.ToString(CultureInfo.InvariantCulture);
        }

        /// <summary>
        /// Gets or sets the <see cref="Object"/> with the specified key.
        /// </summary>
        /// <value></value>
        public object this[string key]
        {
            get
            {
                return this.cache[GetCacheKey(key)];
            }
            set
            {
                this.cache.Insert(GetCacheKey(key), value);
            }
        }


        public void Clear()
        {
            IDictionaryEnumerator cacheNum =this.cache.GetEnumerator();
            ArrayList arl = new ArrayList();
            while (cacheNum.MoveNext())
            {
                arl.Add(cacheNum.Key);
            }
            foreach (string key in arl)
            {
                this.RemoveAll(key);
            }
        }
        /// <summary>
        /// Inserts the specified object to the <see cref="System.Web.Caching.Cache"/> object 
        /// with a cache key to reference its location and using default values provided by 
        /// the <see cref="System.Web.Caching.CacheItemPriority"/> enumeration.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="value">The value.</param>
        public void Insert(string key, object value)
        {
            if (value == null)
                throw new ArgumentNullException("value", "Cannot cache a null object.");
            this.cache.Insert(GetCacheKey(key), value);
        }

        public void Update(string key, object value)
        {
            if (cache[key] != null)
            {
                cache[key] = value;
            }
        }

        /// <summary>
        /// <para>Inserts the specified object to the <see cref="System.Web.Caching.Cache"/> object 
        /// with a cache key to reference its location and using default values provided by 
        /// the <see cref="System.Web.Caching.CacheItemPriority"/> enumeration.
        /// </para>
        /// <para>
        /// Allows specifying a general cache duration.
        /// </para>
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="value">The value.</param>
        /// <param name="cacheDuration">The cache duration.</param>
        public void Insert(string key, object value, CacheDuration cacheDuration)
        {
            if (value == null)
                throw new ArgumentNullException("value", "Cannot cache a null object.");

            this.cache.Insert(GetCacheKey(key), value, null, DateTime.Now.AddMinutes((int)cacheDuration), TimeSpan.Zero, CacheItemPriority.Normal, null);
        }

        /// <summary>
        /// <para>Inserts the specified object to the <see cref="System.Web.Caching.Cache"/> object 
        /// with a cache key to reference its location and using default values provided by 
        /// the <see cref="System.Web.Caching.CacheItemPriority"/> enumeration.
        /// </para>
        /// <para>
        /// Allows specifying a <see cref="CacheDependency"/>
        /// </para>
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="value">The value.</param>
        /// <param name="cacheDependency">The cache dependency.</param>
        public void Insert(string key, object value, CacheDependency cacheDependency)
        {
            if (value == null)
                throw new ArgumentNullException("value", "Cannot cache a null object.");

            this.cache.Insert(GetCacheKey(key), value, cacheDependency);
        }

        /// <summary>
        /// Retrieves the specified item from the <see cref="System.Web.Caching.Cache"/>.
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public object Get(string key)
        {
            return this.cache.Get(GetCacheKey(key));
        }

        public T Get<T>(string Key)
        {
            object obj = this.Get(Key);
            if (obj is T)
            {
                return (T)obj;
            }
            else
            {
                return default(T);
            }
        }

        /// <summary>
        /// Removes the specified item from the cache.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <returns></returns>
        public object Remove(string key)
        {
            return this.cache.Remove(GetCacheKey(key));
        }

        public void RemoveAll(string key)
        {
            this.cache.Remove(key);
        }

        /// <summary>
        /// Returns an enumerator that can iterate through a collection.
        /// </summary>
        /// <returns>
        /// An <see cref="T:System.Collections.IEnumerator"/>
        /// that can be used to iterate through the collection.
        /// </returns>
        public IEnumerator GetEnumerator()
        {
            return this.cache.GetEnumerator();
        }
    }

    /// <summary>
    /// 缓存持续时间
    /// </summary>
    public enum CacheDuration
    {
        None = 0,
        Short = 3,
        Medium = 5,
        Long = 10
    };

    public class ContentCache<T>
    {
        public static T Get(string Key)
        {
            ContentCache cache = ContentCache.Instantiate();
            object obj = cache.Get(Key);
            if (obj is T)
            {
                return (T)obj;
            }
            else
            {
                return default(T);
            }
        }

        public static bool Update(string Key, T Value)
        {
            T me = Get(Key);
            if (me == null)
            {
                return false;
            }
            me = Value;
            return true;
        }
    }
}
